"use strict";

var router = require("router"),
    TokenService = require("router").TokenService,
    mongo = require('./core/mongoservice'),
    ObjectId = require('mongodb').ObjectID,
    Q = require('q');

function ShopService() {
    console.log("ShopService constructor");
}
ShopService.prototype = Object.create(TokenService.prototype);
ShopService.prototype.constructor = ShopService;

ShopService.prototype.save = function (request, response, promise) {
    return promise.then(function (self) {
        //self.identify(request, response);

        return self.mongoSave(request.body).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getByLogin = function (request, response, promise) {
    return promise.then(function (self) {

        var login = decodeURIComponent(request.params.login);
        
        return self.mongoGetPageByLogin(login).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var shopId = request.payload.shop.id;

        return self.mongoGetPageById(shopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getByGps = function (request, response, promise) {
    return promise.then(function (self) {
        
        var lng = parseFloat(request.query.lng);
        var lat = parseFloat(request.query.lat);

        return self.mongoGetPageByGps(lng, lat).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getNearestShopById = function (request, response, promise) {
    return promise.then(function (self) {

        var skip = parseInt(request.query.skip);
        var limit = parseInt(request.query.limit);

        var shopId = request.params.shopId;

        return self.mongoGetNearestShopById(shopId, { skip: skip, limit: limit }).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};



ShopService.prototype.addUserSubscriberFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);
        
        var userId = request.payload.user.id;
        var shopId = request.body.shopId;
        
        return self.mongoAddUserSubscriber(shopId, userId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.addShopSubscriberFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);
        
        var subscriberShopId = request.payload.shop.id;
        var shopId = request.body.shopId;

        return self.mongoAddShopSubscriber(shopId, subscriberShopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.removeUserSubscriberFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var userId = request.payload.user.id;
        var shopId = request.body.shopId;

        return self.mongoRemoveUserSubscriber(shopId, userId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.removeShopSubscriberFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var subscriberShopId = request.payload.shop.id;
        var shopId = request.body.shopId;

        return self.mongoRemoveShopSubscriber(shopId, subscriberShopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getUserSubscribersFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var skip = parseInt(request.query.skip);
        var limit = parseInt(request.query.limit);

        var shopId = request.payload.shop.id;

        return self.mongoGetUserSubscribers(shopId, { skip: skip, limit: limit }).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};
ShopService.prototype.getShopSubscribersFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);
        
        var skip = parseInt(request.query.skip);
        var limit = parseInt(request.query.limit);

        var shopId = request.payload.shop.id;
        
        return self.mongoGetShopSubscribers(shopId, { skip: skip, limit: limit }).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getShopSubscriptionsFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);
        
        var skip = parseInt(request.query.skip);
        var limit = parseInt(request.query.limit);

        var shopId = request.payload.shop.id;
        
        return self.mongoGetShopSubscriptions(shopId, { skip: skip, limit: limit }).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};


ShopService.prototype.getFullById = function (request, response, promise) {
    return promise.then(function (self) {
        var shopId = request.params.shopId;
        return self.mongoGetFullById(shopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

ShopService.prototype.getFullFromToken = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var shopId = request.payload.shop.id;

        return self.mongoGetFullById(shopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};
ShopService.prototype.remove = function (request, response, promise) {
    return promise.then(function (self) {
        self.identify(request, response);

        var shopId = request.body.shopId;

        return self.mongoRemove(shopId).then(function (shop) {
            return response.send({ request: request, content: shop });
        });
    });
};

/*-------------------------------------------------------*/
/*mongo daf*/
ShopService.prototype.mongoSave = function (shop) {
    if (!shop) throw new Error("shop is not defined.");
    var self = this;

    if (shop._id) return self.mongoUpdate(shop);
    else return self.mongoInsert(shop); 
}

ShopService.prototype.mongoInsert = function (shop) {
    if (!shop) throw new Error("shop is not defined.");
    var self = this;

    var employees = shop.users.employees.reduce(function (previous, current) {
        previous.push({ id: new ObjectId(current._id) });
        return previous;
    }, []);

    shop.users.employees = [];
    shop.users = shop.users || { subscribers: [], near: [], employees: [] };
    shop.shops = shop.shops || { subscribers: [], near: [] };
    shop.dates.creation = new Date();

    return require("./referenceservice").mongoIsLoginAuthorized(shop.login).then(function (res) {
        return self.updateTags(shop).then(function (shop) {
            return self.validate(shop).then(function (shop) {
                return mongo.insert('shops', shop).then(function (shops) {
                    var shop = shops[0];
                    return require("./tagservice").mongoSaveTags(shop.tags).then(function () {
                        return self.mongoSaveResearch(shop).then(function () {
                            return shop;
                        });
                    });
                });
            });
        });
    }).then(function (shop) {
        return self.mongoAddEmployees(shop._id, employees).then(function () {
            return self.mongoLocalizeShop(shop).then(function () {
                return require("./referenceservice").mongoInsert(shop.login, shop._id, "shop").then(function () {
                    return self.mongoGetById(shop._id);
                });
            });
        });
    });
};

ShopService.prototype.mongoUpdate = function (shop) {
    if (!shop) throw new Error("shop is not defined.");
    var self = this;

    shop._id = new ObjectId(shop._id);
    shop.categories.forEach(function (item) {
        delete item._id;
    });

    var employees = shop.users.employees.reduce(function (previous, current) {
        var id = current._id || current.id; /*new value use _id, because it was loaded from db*/
        previous.push({ id: new ObjectId(id) });
        return previous;
    }, []);

    shop.users.employees = [];
    return self.updateTags(shop).then(function (shop) {
        return self.mongoGetById(shop._id).then(function (oldShop) {
            shop.login = oldShop.login; //login can not be modified.
            return self.validate(shop).then(function (shop) {
                return self.mongoRemoveEmployees(shop._id, oldShop.users.employees).then(function () {
                    return self.mongoUnlocalizeShop(shop._id).then(function () {
                        return require("./tagservice").mongoSaveTags(shop.tags).then(function(){
                            return mongo.update('shops', { _id: shop._id }, shop).then(function (res) {
                                return self.mongoAddEmployees(shop._id, employees).then(function () {
                                    return self.mongoLocalizeShop(shop).then(function () {
                                        return self.mongoGetById(shop._id);
                                    });
                                });
                            });
                        });
                    });
                });
            });
        });
    });
};

ShopService.prototype.mongoRemove = function (shopId) {
    if (!shopId) throw new Error("shopId is not defined.");
    var self = this;

    shopId = new ObjectId(shopId);

    return self.mongoGetById(shopId).then(function (shop) {
        return self.mongoRemoveEmployees(shop._id, shop.users.employees).then(function () {
            return self.mongoUnlocalizeShop(shop._id).then(function () {
                return mongo.remove('shops', { id: shop._id }).then(function () { //move to archive
                    return mongo.insert('shops.archives', shop).then(function () {
                        return mongo.findOne('shops.reports', { "shop.id": shop._id }).then(function (report) {
                            return mongo.remove('shops.reports', { "shop.id": shop._id }).then(function () {  //move report to archive
                                return mongo.insert('shops.reports.archives', report).then(function () {
                                    return require("./referenceservice").mongoRemove(shop._id, "shop");
                                });
                            });
                        });
                    });
                });
            });
        });
    });
};

ShopService.prototype.mongoGetById = function (shopId) {
    if (!shopId) throw new Error("shopId is not defined.");

    return mongo.findOne('shops', { _id: new ObjectId(shopId) });
};

ShopService.prototype.mongoGetByLogin = function (login) {
    if (!login) throw new Error("login is not defined.");

    return mongo.findOne('shops', { login: login }).then(function (shop) {
        if (!shop) throw new Error("Shop doesn't exist.");
        return shop;
    });
};

ShopService.prototype.mongoGetPageById = function (shopId) {
    var self = this;

    return self.mongoGetById(shopId).then(function (shop) {
        return self.createShopPage(shop);
    });
};

ShopService.prototype.mongoGetPageByLogin = function (login) {
    var self = this;

    return self.mongoGetByLogin(login).then(function (shop) {
        return self.createShopPage(shop);
    });
};

ShopService.prototype.mongoGetFullById = function (shopId) {
    if (!shopId) throw new Error("shopId is not defined.");
    var self = this;

    return self.mongoGetById(shopId).then(function (shop) {
        return self.mongoGetEmployees(shopId).then(function (users) {
            shop.users.employees = users.reduce(function (previous, current) {
                previous.push({
                    id: current._id,
                    login: current.login
                });
                return previous;
            }, []);
            return shop;
        });
    });
};

ShopService.prototype.mongoGetPageByGps = function (lng, lat, options) {
    if (!lng) throw new Error("lng is not defined.");
    if (!lat) throw new Error("lat is not defined.");
    var self = this;

    var coordinates = [lng, lat];
    return mongo.findOne('shops', { "location.loc.coordinates": coordinates }).then(function (shop) {
        if(!shop) throw new Error("Unknown shop with coordinates: " + JSON.stringify(coordinates));    
        return self.createShopPage(shop);
    });
};


ShopService.prototype.mongoGetNearestShopById = function (shopId, options) {
    var self = this;

    var opts = {};
    options = options || {}
    if (options.limit) opts.limit = options.limit;
    if (options.skip) opts.skip = options.skip;
    opts.sort = {"name": 1};

    shopId = new ObjectId(shopId);

    return mongo.find('shops', { "shops.near.id": shopId }, opts).then(function (cursor) {
        return Q.ninvoke(cursor, 'toArray').then(function (shops) {
            return shops.reduce(function (previous, current) {
                previous.push(self.createShopPage(current));
                return previous;
            }, []);
        });
    });
};


ShopService.prototype.mongoAddEmployee = function (shopId, userId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userId) throw new Error("userId is not defined.");

    //faire un test pour savoir si 'utilisateur est déjà membre
    var usr = { id: new ObjectId(userId) };
    var shp = { id: new ObjectId(shopId) };

    return mongo.update('shops', { _id: shp.id }, { $push: { "users.employees": usr} }).then(function () {
        return mongo.update('users', { _id: usr.id }, { $push: { "shops.employers": shp} });
    });
};

ShopService.prototype.mongoAddEmployees = function (shopId, userIds) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userIds) throw new Error("userIds is not defined.");
    var self = this;

    var shopId = new ObjectId(shopId);

    var promises = []

    userIds.forEach(function (item) {
        promises.push(self.mongoAddEmployee(shopId, item.id)) //add employee
    });
    return Q.all(promises)
};

ShopService.prototype.mongoRemoveEmployee = function (shopId, userId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userId) throw new Error("userId is not defined.");
    var self = this;

    //faire un test pour savoir si 'utilisateur est déjà membre
    var usr = { id: new ObjectId(userId) };
    var shp = { id: new ObjectId(shopId) };

    return mongo.update('shops', { _id: shp.id }, { $pull: { "users.employees": usr} }).then(function () {
        return mongo.update('users', { _id: usr.id }, { $pull: { "shops.employers": shp} });
    });
};

ShopService.prototype.mongoRemoveEmployees = function (shopId, userIds) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userIds) throw new Error("userIds is not defined.");
    var self = this;

    shopId = new ObjectId(shopId);
    var promises = []

    userIds.forEach(function (item) {
        promises.push(self.mongoRemoveEmployee(shopId, item.id)) //remove employee
    });
    return Q.all(promises)
};

ShopService.prototype.mongoAddUserSubscriber = function (shopId, userId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userId) throw new Error("userId is not defined.");
    var self = this;

    //faire un test pour savoir si 'utilisateur est déjà membre
    //on fait un requête geo pour avoir la distance entre la boutique et l'utilisateur
    return self.mongoGetById(shopId).then(function (shop) {
        var options = {
            spherical: true,
            distanceMultiplier: 0.6371,
            query: { _id: new ObjectId(userId) }
        };
        return mongo.geoNear('users', shop.location.loc.coordinates[0], shop.location.loc.coordinates[1], options).then(function (doc) {
            if (doc.results.length != 1) throw new Error("Failed to retrieve distance between user and shop.");

            var result = doc.results[0];
            var usr = { id: new ObjectId(userId), distanceM: result.dis };
            var shp = { id: new ObjectId(shopId), distanceM: result.dis };

            return mongo.update('shops', { _id: shp.id }, { $push: { "users.subscribers": usr} }).then(function () {
                return mongo.update('alerts', { "shop.id": shp.id }, { $push: { "users.subscribers": usr} }, {multi: true}).then(function () {
                    return mongo.update('users', { _id: usr.id }, { $push: { "shops.subscriptions": shp} })
                });
            });
        });
    }).then(function (data) {
        return self.mongoGetById(shopId).then(function (shop) {
            return require("./shopreportservice").mongoUpdate(shop).then(function () {
                return shop;
            });
        });
    });
};

ShopService.prototype.mongoAddShopSubscriber = function (shopId, subscriberShopId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!subscriberShopId) throw new Error("subscriberShopId is not defined.");
    var self = this;

    //faire un test pour savoir si 'utilisateur est déjà membre
    //on fait un requête geo pour avoir la distance entre les 2 boutiques
    return self.mongoGetById(shopId).then(function (shop) {
        var options = {
            spherical: true,
            distanceMultiplier: 0.6371,
            query: { _id: new ObjectId(subscriberShopId) }
        };
        return mongo.geoNear('shops', shop.location.loc.coordinates[0], shop.location.loc.coordinates[1], options).then(function (doc) {
            if (doc.results.length != 1) throw new Error("Failed to retrieve distance between user and shop.");

            var result = doc.results[0];
            var shpS = { id: new ObjectId(subscriberShopId), distanceM: result.dis };
            var shp = { id: new ObjectId(shopId), distanceM: result.dis };

            return mongo.update('shops', { _id: shp.id }, { $push: { "shops.subscribers": shpS} }).then(function () {
                return mongo.update('alerts', { "shop.id": shp.id }, { $push: { "shops.subscribers": shpS} }, {multi: true}).then(function (res) {
                    return mongo.update('shops', { _id: shpS.id }, { $push: { "shops.subscriptions": shp} })
                });
            });
        });
    }).then(function (data) {
        return self.mongoGetById(shopId).then(function (shop) {
            return require("./shopreportservice").mongoUpdate(shop).then(function () {
                return shop;
            });
        });
    });
};

ShopService.prototype.mongoRemoveUserSubscriber = function (shopId, userId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!userId) throw new Error("userId is not defined.");
    var self = this;

    //faire un test pour savoir si 'utilisateur est déjà membre
    var usr = { id: new ObjectId(userId) };
    var shp = { id: new ObjectId(shopId) };

    return mongo.update('shops', { _id: shp.id }, { $pull: { "users.subscribers": usr } }).then(function () {
        return mongo.update('alerts', { "shop.id": shp.id }, { $pull: { "users.subscribers": usr} }, {multi: true}).then(function () {
            return mongo.update('users', { _id: usr.id }, { $pull: { "shops.subscriptions": shp } });
        });
    }).then(function (data) {
        return self.mongoGetById(shp.id).then(function (shop) {
            return require("./shopreportservice").mongoUpdate(shop).then(function () {
                return shop;
            });
        });
    });
};

ShopService.prototype.mongoRemoveShopSubscriber = function (shopId, subscriberShopId) {
    if (!shopId) throw new Error("shopId is not defined.");
    if (!subscriberShopId) throw new Error("subscriberShopId is not defined.");
    var self = this;

    //faire un test pour savoir si 'utilisateur est déjà membre
    var shpS = { id: new ObjectId(subscriberShopId) };
    var shp = { id: new ObjectId(shopId) };

    return mongo.update('shops', { _id: shp.id }, { $pull: { "shops.subscribers": shpS } }).then(function () {
        return mongo.update('alerts', { "shop.id": shp.id }, { $pull: { "shops.subscribers": shpS} }, {multi: true}).then(function () {
            return mongo.update('shops', { _id: shpS.id }, { $pull: { "shops.subscriptions": shp } });
        });
    }).then(function (data) {
        return self.mongoGetById(shp.id).then(function (shop) {
            return require("./shopreportservice").mongoUpdate(shop).then(function () {
                return shop;
            });
        });
    });
};

ShopService.prototype.mongoGetUserSubscribers = function (shopId, options) {
    if (!shopId) throw new Error("shopId is not defined.");

    var opts = {};
    options = options || {}
    if (options.limit) opts.limit = options.limit;
    if (options.skip) opts.skip = options.skip;
    opts.sort = {"login": 1};

    var query = { "shops.subscriptions.id": new ObjectId(shopId) };

    return mongo.find('users', query, opts).then(function (cursor) {
        return Q.ninvoke(cursor, 'toArray');
    });
};

ShopService.prototype.mongoGetShopSubscribers = function (shopId, options) {
    if (!shopId) throw new Error("shopId is not defined.");

    var opts = {};
    options = options || {}
    if (options.limit) opts.limit = options.limit;
    if (options.skip) opts.skip = options.skip;
    opts.sort = {"name": 1};

    var query = { "shops.subscriptions.id": new ObjectId(shopId) };

    return mongo.find('shops', query, opts).then(function (cursor) {
        return Q.ninvoke(cursor, 'toArray');
    });
};

ShopService.prototype.mongoGetShopSubscriptions = function (shopId, options) {
    if (!shopId) throw new Error("shopId is not defined.");

    var opts = {};
    options = options || {}
    if (options.limit) opts.limit = options.limit;
    if (options.skip) opts.skip = options.skip;
    opts.sort = {"name": 1};

    var query = { "shops.subscribers.id": new ObjectId(shopId) };

    return mongo.find('shops', query, opts).then(function (cursor) {
        return Q.ninvoke(cursor, 'toArray');
    });
};

ShopService.prototype.mongoGetEmployees = function (shopId) {
    if (!shopId) throw new Error("shopId is not defined.");

    shopId = new ObjectId(shopId);

    return mongo.find('users', { "shops.employers.id": shopId }).then(function (cursor) {
        return Q.ninvoke(cursor, 'toArray');
    });
};

ShopService.prototype.mongoLocalizeShop = function (shop) {
    if (!shop) throw new Error("shop is not defined.");
    var self = this;

    var options = {
        spherical: true,
        maxDistance: 10000 / 0.6371, //10km
        distanceMultiplier: 0.6371
    };

    //recherche les utilisateurs dans le périmètre de la boutique
    return mongo.geoNear('users', shop.location.loc.coordinates[0], shop.location.loc.coordinates[1], options).then(function (doc) { //search users un the perimeter
        var promises = [];

        var shp = { id: shop._id };
        doc.results.forEach(function (item) {
            if (item.obj.config.distanceM < item.dis) {
                return;
            }
            var usr = { id: item.obj._id, distanceM: item.dis };
            var promise = mongo.update('users', { _id: usr.id }, { $push: { "shops.near": shp} }).then(function () {
                return mongo.update('shops', { _id: shp.id }, { $push: { "users.near": usr} });
            });
            promises.push(promise);
        });
        return Q.all(promises);
    }).then(function () {
        //recherche les autres boutiques dans le périmètre de la boutique
        return mongo.geoNear('shops', shop.location.loc.coordinates[0], shop.location.loc.coordinates[1], options).then(function (doc) {
            var promises = [];
            doc.results.forEach(function (item) {

                var shp0 = { id: shop._id, distanceM: item.dis };
                var shp1 = { id: item.obj._id, distanceM: item.dis };
                if (shp0.id.toString() == shp1.id.toString()) {
                    return;
                }

                var promise = mongo.update('shops', { _id: shp0.id }, { $push: { "shops.near": shp1} }).then(function () {
                    return mongo.update('shops', { _id: shp1.id }, { $push: { "shops.near": shp0} }).then(function () {
                        return mongo.update('alerts', { "shop.id": shp1.id }, { $push: { "shops.near": shp0} }, {multi: true});
                    });
                });
                promises.push(promise);
            });
            return Q.all(promises);
        });
    }).then(function () {
        return self.mongoGetById(shop._id).then(function (shop) {
            return require("./shopreportservice").mongoInsert(shop).then(function () {
                return shop;
            });
        });
    });
}

ShopService.prototype.mongoUnlocalizeShop = function (shopId) {
    if (!shopId) throw new Error("shopId is not defined.");
    var self = this;

    shopId = new ObjectId(shopId);
    var shp = { id: shopId };

    //mise à jour des utilisateurs
    return mongo.update('users', { }, { $pull: { "shops.near": shp} }, { multi: true }).then(function () {
        return mongo.update('alerts', { "shop.id": shopId }, {$set:{ "users.near":[]}}, {multi: true} ).then(function () {
            return mongo.update('shops', { _id: shp.id }, {$set: {"users.near": []}});
        });
    }).then(function () {
        //mise à jour des utilisateurs
        return mongo.update('shops', { }, { $pull: { "shops.near": shp} }, { multi: true }).then(function () {
            return mongo.update('alerts', { "shop.id": shopId }, {$set:{ "shops.near":[]}} , {multi: true}).then(function () {
                return mongo.update('shops', { _id: shp.id }, {$set: {"shops.near": []}});
            });
        });
    }).then(function () {
        return self.mongoGetById(shopId).then(function (shop) {
            return require("./shopreportservice").mongoInsert(shop).then(function () {
                return shop;
            });
        });
    });
}

/*--------------------------------------------*/
/*Common*/
ShopService.prototype.createShopPage = function (shop) {
    if (!shop) throw new Error("shop is not defined.");
    var self = this;

    var today = new Date();
    var alive = shop.alerts.alive.reduce(function (previous, current) {
        if (current.maturity > today) previous.push(current);
        return previous;
    }, []);

    //overwrite users & shops
    shop.users = {
        subscribers: {
            total: shop.users.subscribers.length
        },
        near: {
            total: shop.users.near.length
        }
    };
    shop.shops = {
        subscribers: {
            total: shop.shops.subscribers.length
        },
        near: {
            total: shop.shops.near.length
        }
    };
    shop.alerts = {
        total: shop.alerts.total,
        alive: {
            total: alive.length
        }
    }

    return shop;
}

ShopService.prototype.updateTags = function (shop) {
    return require("./tagservice").extractHashtag(shop.description).then(function (res) {
        shop.tags = [];

        shop.tags.push(shop.login);
        shop.tags.push(shop.name);
        if (shop.location.city) shop.tags.push(shop.location.city);
        if (shop.location.departement) shop.tags.push(shop.location.departement);
        if (shop.location.postal_code) shop.tags.push(shop.location.postal_code);
        if (shop.location.route) shop.tags.push(shop.location.route);
        if (shop.location.neighborhood) shop.tags.push(shop.location.neighborhood);
        
        shop.categories.forEach(function (category) {
            shop.tags.push(category.name);
        });

        res.tags.forEach(function (tag) {
            if (shop.tags.indexOf(tag) == -1) shop.tags.push(tag);
        });

        return shop;
    });
}

ShopService.prototype.mongoSaveResearch = function (shop) {
    var research = [];

    if (shop.location.city) {
        research.push(shop.location.city);
        research.push(shop.name + ", " + shop.location.city);

        shop.categories.forEach(function(category){
            research.push(category.name + ", " + shop.location.city);
            research.push(shop.location.city + ", " + category.name);
        });

        if (shop.location.route) research.push(shop.location.route + ", " + shop.location.city);
        if (shop.location.neighborhood) {
            research.push(shop.location.neighborhood + ", " + shop.location.city);
            research.push(shop.location.city + ", " + shop.location.city.neighborhood);
        }
    }
    return require("./researchservice").mongoSaveList(research);
};

ShopService.prototype.validate = function (shop) {
    return Q.fcall(function () {
        if (!shop) throw new Error("shop is not defined.");
        var self = this;

        if (!shop.login || shop.login.length == 0) throw new Error("Login is empty");
        if (!/(^[\w|[0-9]|áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ\']{3,}$)/gi.test(shop.login)) throw new Error("Bad login format.");

        if (shop.contact.email && shop.contact.email.length > 0) {
            if (!/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(shop.contact.email)) throw new Error("Bad email format.");
        }

        if (shop.contact.tel && shop.contact.tel.length > 0) {
            if (!/^((\+|00)33\s?|0)[1-9](\s?\d{2}){4}$/i.test(shop.contact.tel)) throw new Error("Bad phone number format.");
        }

        if (!shop.location) throw new Error("Location is empty.");
        if (!shop.location.address) throw new Error("Location is empty.");
        if (shop.location.loc.coordinates.length != 2) throw new Error("Address is not well defined.");
        if (!shop.categories || shop.categories.length == 0) throw new Error("Category is not defined.");

        return shop;
    });
};

exports = module.exports = new ShopService();